home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
mxcode
/
muspl150
/
dump_mus.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-29
|
10KB
|
465 lines
/*
* Name: MUS File Dumper
* Version: 1.40
* Author: Vladimir Arnost (QA-Software)
* Last revision: Sep-29-1994
* Compiler: Borland C++ 3.1
*
*/
/*
* Revision History:
*
* Aug-1-1994 V1.00 V.Arnost
* Written from scratch
* Aug-9-1994 V1.20 V.Arnost
* Fixed some minor bugs
* Sep-16-1994 V1.30 V.Arnost
* Added command line parser
* Added single channel and single event type dump
* Sep-29-1994 V1.40 V.Arnost
* Fixed improper instrument number handling
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define VERSION "1.40"
#define COPYRIGHT "MUS File Dump Version "VERSION" (c) 1994 QA-Software"
#ifndef __386__
typedef unsigned char BYTE;
typedef unsigned int WORD;
#endif
typedef unsigned long DWORD;
struct MUSheader {
char ID[4]; // identifier "MUS" 0x1A
WORD scoreLen;
WORD scoreStart;
WORD channels;
WORD dummy1;
WORD instrCnt;
WORD dummy2;
// WORD instruments[];
} header;
WORD instruments[64];
static char *instrname[] =
{"Acoustic Grand Piano",
"Bright Acoustic Piano",
"Electric Grand Piano",
"Honky-tonk Piano",
"Rhodes Paino",
"Chorused Piano",
"Harpsichord",
"Clavinet",
"Celesta",
"Glockenspiel",
"Music Box",
"Vibraphone",
"Marimba",
"Xylophone",
"Tubular-bell",
"Dulcimer",
"Hammond Organ",
"Percussive Organ",
"Rock Organ",
"Church Organ",
"Reed Organ",
"Accordion",
"Harmonica",
"Tango Accordion",
"Acoustic Guitar (nylon)",
"Acoustic Guitar (steel)",
"Electric Guitar (jazz)",
"Electric Guitar (clean)",
"Electric Guitar (muted)",
"Overdriven Guitar",
"Distortion Guitar",
"Guitar Harmonics",
"Acoustic Bass",
"Electric Bass (finger)",
"Electric Bass (pick)",
"Fretless Bass",
"Slap Bass 1",
"Slap Bass 2",
"Synth Bass 1",
"Synth Bass 2",
"Violin",
"Viola",
"Cello",
"Contrabass",
"Tremolo Strings",
"Pizzicato Strings",
"Orchestral Harp",
"Timpani",
"String Ensemble 1",
"String Ensemble 2",
"Synth Strings 1",
"Synth Strings 2",
"Choir Aahs",
"Voice Oohs",
"Synth Voice",
"Orchestra Hit",
"Trumpet",
"Trombone",
"Tuba",
"Muted Trumpet",
"French Horn",
"Brass Section",
"Synth Brass 1",
"Synth Bass 2",
"Soprano Sax",
"Alto Sax",
"Tenor Sax",
"Baritone Sax",
"Oboe",
"English Horn",
"Bassoon",
"Clarinet",
"Piccolo",
"Flute",
"Recorder",
"Pan Flute",
"Bottle Blow",
"Shakuhachi",
"Whistle",
"Ocarina",
"Lead 1 (square)",
"Lead 2 (sawtooth)",
"Lead 3 (calliope)",
"Lead 4 (chiffer)",
"Lead 5 (charang)",
"Lead 6 (voice)",
"Lead 7 (5th sawtooth)",
"Lead 8 (bass & lead)",
"Pad 1 (new age)",
"Pad 2 (warm)",
"Pad 3 (polysynth)",
"Pad 4 (choir)",
"Pad 5 (bowed glass)",
"Pad 6 (metal)",
"Pad 7 (halo)",
"Pad 8 (sweep)",
"FX 1 (rain)",
"FX 2 (soundtrack)",
"FX 3 (crystal)",
"FX 4 (atmosphere)",
"FX 5 (brightness)",
"FX 6 (goblin)",
"FX 7 (echo drops)",
"FX 8 (star-theme)",
"Sitar",
"Banjo",
"Shamisen",
"Koto",
"Kalimba",
"Bag Pipe",
"Fiddle",
"Shanai",
"Tinkle Bell",
"Agogo",
"Steel Drums",
"Woodblock",
"Taiko Drum",
"Melodic Tom",
"Synth Drum",
"Reverse Cymbal",
"Guitar Fret Noise",
"Breath Noise",
"Seashore",
"Bird Tweet",
"Telephone Ring",
"Helicopter",
"Applause",
"Gun Shot"};
static char *percussion[] =
{"Acoustic Bass Drum",
"Acoustic Bass Drum",
"Slide Stick",
"Acoustic Snare",
"Hand Clap",
"Electric Snare",
"Low Floor Tom",
"Closed High-Hat",
"High Floor Tom",
"Pedal High Hat",
"Low Tom",
"Open High Hat",
"Low-Mid Tom",
"High-Mid Tom",
"Crash Cymbal 1",
"High Tom",
"Ride Cymbal 1",
"Chinses Cymbal",
"Ride Bell",
"Tambourine",
"Splash Cymbal",
"Cowbell",
"Crash Cymbal 2",
"Vibraslap",
"Ride Cymbal 2",
"High Bongo",
"Low Bango",
"Mute High Conga",
"Open High Conga",
"Low Conga",
"High Timbale",
"Low Timbale",
"High Agogo",
"Low Agogo",
"Cabasa",
"Maracas",
"Short Whistle",
"Long Whistle",
"Short Guiro",
"Long Guiro",
"Claves",
"High Wood Block",
"Low Wood Block",
"Mute Cuica",
"Open Cuica",
"Mute Triangle",
"Open Triangle"};
/* Command-line parameters */
char *musname = NULL;
int help = 0;
int onlychannel = -1;
int onlyevent = -1;
char *note2name(BYTE note)
{
static char name[8] = "";
static char *notes[] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};
static char *octaves[] = {"-0", "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", "-9", "-10"};
strcpy(name, notes[note % 12]);
strcat(name, octaves[note / 12]);
return name;
}
char *instr2name(WORD instr)
{
if (instr < 128)
return instrname[instr];
else if (instr >= 135 && instr < (135+47)) // there are 47 percussive instruments
return percussion[instr-135];
else
return "*Unknown*";
}
int dispatchOption(char *option)
{
int n;
switch (*option) {
case '?':
case 'H': // help
help = 1;
break;
case 'C': // channel
n = atoi(option+1);
if (onlychannel == -1) onlychannel = 0;
onlychannel |= 1 << n;
break;
case 'E': // event
n = atoi(option+1);
if (onlyevent == -1) onlyevent = 0;
onlyevent |= 1 << n;
break;
default:
return -1;
}
return 0;
}
main(int argc, char *argv[])
{
FILE *f;
WORD i;
DWORD delay = 0;
puts(COPYRIGHT);
while (argv++, --argc)
{
strupr(*argv);
if (**argv == '/' || **argv == '-')
{
if (dispatchOption(*argv+1))
{
printf("Invalid option %s\n", *argv);
return 2;
}
} else {
if (!musname)
musname = *argv;
else {
printf("Too many filenames.\n");
return 3;
}
}
}
if (!musname || help)
{
puts("Syntax:\n"
" DUMP_MUS filename.MUS [options]\n"
"Options:\n"
" /Cn Dump events in channel number n only.\n"
" /En Dump events of type n only. n is 0-7."
);
return 1;
}
if ( (f = fopen(musname, "rb")) == NULL)
{
printf("Can't open file %s\n", musname);
return 2;
}
fread(&header, sizeof header, 1, f);
if (header.ID[0] != 'M' ||
header.ID[1] != 'U' ||
header.ID[2] != 'S' ||
header.ID[3] != 0x1A)
{
puts("Bad file.");
fclose(f);
return 3;
}
fread(&instruments, sizeof(WORD), header.instrCnt, f);
printf("Score Length\t\t%04Xh (%u bytes)\n", header.scoreLen, header.scoreLen);
printf("Score Start\t\t%04Xh\n", header.scoreStart);
printf("Channels\t\t%d\n", header.channels);
printf("Instruments Used\t%d\n", header.instrCnt);
for (i = 0; i < header.instrCnt; i++)
{
register WORD ins = instruments[i];
printf(" %3d %s\n", ins, instr2name(ins));
/* printf(" %3d %s\n", ins, ins < 128 ? instrname[ins] :
(ins < (135+47) ? percussion[ins-135] : "*Unknown*") ); */
}
printf("\n");
while (!feof(f))
{
int cmd, channel, timemark, note, volume, value, show, fulldump;
DWORD offs = ftell(f);
if ( (value = fgetc(f)) == -1)
break;
timemark = value & 0x80;
channel = value & 0x0F;
cmd = (value >> 4) & 0x07;
fulldump = onlychannel == -1 && onlyevent == -1;
show = fulldump || cmd == 6 || ((onlychannel & (1 << channel)) &&
(onlyevent & (1 << cmd)));
if (show)
{
if (delay)
{
printf("\t\t\tdelay: %ld\n", delay);
delay = 0;
}
printf("%06lX: %02X ", offs, value);
}
switch (cmd) {
case 0: // release note
note = fgetc(f);
if (show)
printf("%02X\t\t#%d: release note %d (%s)\n",
note, channel, note, channel == 15 ? percussion[note-35] :
note2name(note));
break;
case 1: // play note
note = fgetc(f);
if (note & 0x80)
{
volume = fgetc(f);
if (show)
printf("%02X %02X\t#%d: play note %d (%s), volume %d\n",
note, volume, channel, note & 0x7F,
channel == 15 ? instr2name((note & 0x7F)+100) :
note2name(note & 0x7F), volume);
} else
if (show)
printf("%02X\t\t#%d: play note %d (%s)\n",
note, channel, note, channel == 15 ?
instr2name(note+100) : note2name(note));
break;
case 2: // pitch wheel
value = fgetc(f);
if (show)
printf("%02X\t\t#%d: pitch wheel %+d\n", value, channel, value - 0x80);
break;
case 5: // ???
case 7: // ???
value = fgetc(f);
if (show)
printf("%02X\t\t#%d: unknown command, parameter %d\n", value, channel, value);
break;
case 3: // set ???
value = fgetc(f);
if (show)
printf("%02X\t\t#%d: set ??? to %d\n", value, channel, value);
break;
case 4: // change control
volume = fgetc(f);
value = fgetc(f);
if (show)
{
printf("%02X %02X\t#%d: ", volume, value, channel);
switch (volume) {
case 0: // change instrument
printf("set instrument %d (%s)\n", value,
value < 128 ? instrname[value] : "*Invalid*");
break;
case 3: // change volume
printf("set volume %d\n", value);
break;
case 4: // change pan
printf("set pan %+d\n", value - 0x40);
break;
default: // ???
printf("set control %d, %d\n", volume, value);
}
}
break;
case 6: // end
printf("\t\t#%d: end of score\n", channel);
break;
}
if (timemark)
{
DWORD time = 0;
BYTE b;
if (fulldump)
printf("%06lX: ", ftell(f));
do {
b = fgetc(f);
if (fulldump)
printf("%02X ", b);
time <<= 7;
time += b & 0x7F;
} while (b & 0x80);
if (fulldump)
printf("\t\tdelay: %ld\n", time);
else
delay += time;
}
}
fclose(f);
return 0;
}